<?php


namespace app\common\service\workflow;

use app\admin\model\Feeitem;
use app\admin\model\ProjectFeeitem;
use app\common\model\workflow\Node;
use app\common\model\workflow\Node as NodeModel;
use app\common\model\workflow\NodeRecord;
use app\common\model\workflow\NodeScope;
use app\common\model\workflow\Template as TemplateModel;
use app\common\model\workflow\Workflow as WFModel;
use think\Exception;
use think\facade\Db;
use think\facade\Log;
use think\facade\Request;

class Workflow
{
    private $flow_no;
    private $flow_detail;
    private $now_node;
    private $now_step;

    /**
     * @var 所有的节点
     */
    private $nodes;
    /**
     * @var 所有的节点人员
     */
    private $scopes;

    /**
     * @var 当前用户
     */
    private $user;

    public function __construct($flow_no, $user)
    {
        $this->flow_no = $flow_no;
        $this->flow_detail = WFModel::with('nodes')->where('flow_no',$flow_no)->find();
        if($this->flow_detail->isEmpty()){
            $this->error('错误的流程信息!');
        }

        $now_step = $this->flow_detail->audit_step;
        $this->now_step = $now_step;
        $this->nodes = $this->flow_detail->nodes->toArray();
        foreach ($this->nodes as $v){
            if($v['step'] == $now_step) {
                $this->now_node = $v;
                break;
            }
        }
        $this->scopes = NodeScope::where('flow_id',$this->flow_detail->id)->select()->toArray();
        $this->user = $user;
    }

    /**
     * 流程开始（流程提审）
     */
    public function start(){
        if($this->now_step != 0 ){
            $this->error('错误的流程状态!');
        }
        $step = $this->flow_detail->audit_step = 2;
        $this->flow_detail->state = 1;
        foreach ($this->nodes as $v){
            if($v['step'] == 1){
                $this->add_record($v,[['scope_id'=>$this->flow_detail->creator_id,'scope_name'=>$this->flow_detail->creator_name]],[],2);
            }
            if($v['step'] == $step) {
                $node = $v;break;
            }
        }
        $scopes = [];
        $ids = [];$names = [];
        foreach ($this->scopes as $v){
            if($v['node_step'] == $step) {
                $scopes[] = $v;
                $ids[] = $v['scope_id'];
                $names[] = $v['scope_name'];
            }
        }
        $this->flow_detail->audit_id = implode(',',$ids);
        $this->flow_detail->audit_name = implode(',',$names);
        $this->flow_detail->save();
        $this->add_record($node, $scopes);
        $this->notify();
    }

    /**
     * 流程审核
     */
    public function audit($audit_data, $user){
        $step = $this->now_step;
        //是否已经审核过了
        $scope = array_filter($this->scopes,function ($v) use ($step,$user){
            return $v['node_step'] == $step && $v['scope_id'] == $user['id'];
        });
        if(count($scope) == 0){
            $this->error('未找到对应的节点人员！');
        }
        $scope_audit = array_filter($scope,function ($v){
            return $v['state'] == 0;
        });
        if(count($scope_audit) == 0){
            $this->error('您已审核过了！');
        }
        $time = time();
        foreach ($scope as $v){
            NodeScope::update(['state'=>1,'audit_time'=>$time],['id'=>$v['id']]);
            $this->add_record($this->now_node,[$v],$audit_data,2);
            foreach ($this->scopes as &$global_scope){
                if($global_scope['id'] == $v['id']){
                    $global_scope['state'] = 1;
                    $global_scope['audit_time'] = $time;
                    break;
                }
            }
        }
        if($audit_data['audit_state'] == 0){
            //如果审批人拒绝 当前流程立即结束
            $this->flow_detail->state = 2;
            $this->flow_detail->complete = time();
            $this->flow_detail->audit_tips = $audit_data['msg'];
            $this->flow_detail->update_time = time();
            $this->flow_detail->save();
            $this->notify($audit_data);
        } else {
            //是否能流转到下一步
            $allow_next = false;
            $not_audit_scopes = [];
            $ids = [];$names = [];
            foreach ($this->scopes as $v){
                if($v['state'] == 0) {
                    $not_audit_scopes[] = $v;
                    $ids[] = $v['scope_id'];
                    $names[] = $v['scope_name'];
                }
            }
            if($this->now_node['node_type'] == 1 && count($not_audit_scopes) == 0){//会签
                $allow_next = true;
            }
            if($this->now_node['node_type'] == 1 && count($not_audit_scopes) < count($this->scopes)) {//或签
                $allow_next = true;
            }
            if($allow_next){
                $this->flow_detail->audit_tips = $audit_data['msg'];
                $this->wf_next();
            }  else {
                $this->flow_detail->audit_id = implode(',',$ids);
                $this->flow_detail->audit_name = implode(',',$names);
                $this->flow_detail->update_time = time();
                $this->flow_detail->save();
            }
        }
    }

    /**
     * 流程 撤销
     * @return void
     */
    public function cancel($user, ){
        $audit_data = [
            "msg" => '申请人撤销申请',
            "audit_state" => 2
        ];
        $this->add_record($this->now_node,[["scope_id" => $user['id'], 'scope_name'=> $user['nickname']]],$audit_data,2);
        $this->flow_detail->state = 2;
        $this->flow_detail->complete = time();
        $this->flow_detail->audit_tips = $audit_data['msg'];
        $this->flow_detail->update_time = time();
        $this->flow_detail->save();
    }

    /**
     * 流程抄送
     */
    private function copy(){
        $step = $this->now_step;
        $scopes = array_filter($this->scopes,function ($v) use($step){
            return $v['node_step'] == $step;
        });
        $this->add_record($this->now_node,$scopes,[],2);
        $this->wf_next();
    }

    /**
     * 流程流转
     * @param  $flow_no 流程编号
     */
    private function wf_next(){
        if($this->flow_detail->audit_step == $this->flow_detail->total_step) {//当前节点是最后一个节点
            $this->flow_detail->state = 3;
            $this->flow_detail->complete = time();
            $this->flow_detail->update_time = time();
            $this->flow_detail->save();
            $this->notify();
        } else {
            //下一个节点判断
            $next_step = ++$this->flow_detail->audit_step;
            $next_node = [];
            foreach ($this->flow_detail->nodes as $v){
                if($v['step'] == $next_step) {
                    $next_node = $v;break;
                }
            }
            $next_node_scopes = [];
            $ids = [];$names = [];
            foreach ($this->scopes as $v){
                if($v['node_step'] == $next_step){
                    $next_node_scopes[] = $v;
                    $ids[] = $v['scope_id'];
                    $names[] = $v['scope_name'];
                }
            }
            if($this->flow_detail->state != 1 && $next_node['node_type'] != 2){//如果当前流程已结束并且下一个节点不是抄送节点
                return ;
            }
            //添加人员记录
            $this->add_record($next_node,$next_node_scopes,[],1);
            $this->flow_detail->audit_id = implode(',',$ids);
            $this->flow_detail->audit_name = implode(',',$names);
            $this->flow_detail->update_time = time();
            $this->flow_detail->save();
            // 如果是抄送节点执行抄送操作
            if(($next_node['node_type']) == 2){
                $this->now_node = $next_node;
                $this->now_step = $next_step;
                $this->copy();
            }
        }
    }

    /**
     * 流程记录
     * @param $node array 节点
     * @param $scopes array 节点人员(具体到人员)
     * @param $audit_data array 审核信息
     * @param $type integer 记录类型 1：操作记录 2:审核记录
     */
    public function add_record($node = [],$scopes = [],$audit_data = [],$type = 1){
        if(is_object($node)) $node = $node->toarray();
        $data = [
            "flow_id" => $node['flow_id'],
            "node_id" => $node['id'],
            "node_step" => $node['step'],
            "node_type" => $node['node_type'],
            "record_type" => $type
        ];
        $NodeRecordModel = new NodeRecord();
        $lists = [];
        $msgs = [
            '1' => '流程待%s审核',
            '2' => '流程抄送给%s',
            '3' => '%s发起审核',
        ];
        foreach ($scopes as $v){
            $temp = $data;
            $temp['scope_id'] = $v['scope_id'];
            $temp['scope_name'] = $v['scope_name'];
            if($node['node_type'] == 1 && $type == 2){
                $temp['attachs'] = isset($audit_data['attachs']) ? (is_array($audit_data['attachs']) ? implode(',', $audit_data['attachs']) : $audit_data['attachs']) : '';
                $temp['msg'] = $audit_data['msg'];
                $temp['audit_state'] = $audit_data['audit_state'];
            } else {
                $temp['msg'] = sprintf($msgs[$node['node_type']],$temp['scope_name']);
            }
            $lists[] = $temp;
        }
        $NodeRecordModel->saveAll($lists);
    }

    private function error($msg){
        throw new Exception($msg);
    }

    private function notify($audit_data = []){
        $WFnotify_data = $this->flow_detail->toArray();
        $WFnotify_data['audit_emp'] = $this->user;
        $WFnotify_data['audit_data'] = $audit_data;

        $model_name = [
            \app\common\model\apply\Reimbursement::class,
            \app\common\model\apply\Advance::class,
            \app\common\model\apply\Payment::class,
            \app\common\model\Project::class
        ][$WFnotify_data['flow_model']-1];

        if($WFnotify_data['flow_model'] == 4) {
            $modelRow = $model_name::where([
                ['id', '=', $WFnotify_data['extend']]
            ])->findOrEmpty();
            $modelRow->budget_audit_state = $WFnotify_data['state'];
        } else {
            $modelRow = $model_name::where([
                ['no', '=', $WFnotify_data['extend']]
            ])->findOrEmpty();
            $modelRow->audit_state = $WFnotify_data['state'];
            $modelRow->wokerflow_id = $WFnotify_data['id'];

            if($WFnotify_data['state'] == 3){
                $modelRow->paid = 1;
            }
            // 驳回 将添加的核算扣除
            if($WFnotify_data['state'] == 2 && $WFnotify_data['flow_model'] <= 3){
                $feeitems = $modelRow['feeitems'];
                if(!is_array($modelRow['feeitems'])){
                    $feeitems = json_decode($feeitems, true);
                }
                foreach ($feeitems as $v) {
                    $sql = 'update ba_project_feeitem set calculate = calculate - '.$v['amount'].' where project_id = '.$modelRow->project_id.' and feeitem_id = '.$v['feeitem_id'];
//                    ProjectFeeitem::where(['project_id' => $modelRow->project_id, 'feeitem_id' => $v['feeitem_id']])->save(['calculate' => ['exp' , 'calculate - '.$v['amount'] ]]);
                    Db::query($sql);
                }

            }
        }
        $modelRow->save();
    }
}